import sys
import re
import os

_target__type_h = "h"
_target__type_m = "m"
_lazy_signal = "lazy"

_ret_rep = "class_return_type"
_ins_rep = "instance_name"
_class_rep = "class_call_type"
_imp_end = "@end"
_get_code_str = f"""

- ({_ret_rep}){_ins_rep} {{
    if(_{_ins_rep} == nil) {{
        _{_ins_rep} = [[{_class_rep} alloc] init];
    }}
    return _{_ins_rep};
}}
"""

file_sep = "."
re_pro = r'@property {0,2}(\([\w\W]*?\))? {0,2}'
re_name_in_pro = re.compile(r'(?<!\w)(?: {0,3})\w+(?: {0,3})(?=;)')
re_type_in_pro = re.compile(r'\w+ {0,2}[ *]{1,5}(?=\w{1,40};)')
re_pro_get_imp = re.compile(r'- {0,2}\(.+?\)\w+?\s*\{')


class OCLazyGen:
    def __init__(self, file_full_path):
        self.file_full_path = file_full_path

    def need_lazy(self) -> (bool, str):
        _pro_reg = re.compile(r'@property.+')
        with open(self.file_full_path) as f:
            file_content = f.read()
        res_list: [str] = _pro_reg.findall(file_content)
        for res_item in res_list:
            if _lazy_signal in res_item:
                return True, res_item
        return False, ""

    def clean_lazy(self, pro_str: str):
        with open(self.file_full_path, 'r') as f_r:
            content = f_r.read()
        with open(self.file_full_path, 'w') as f_r:
            rep_new_str = pro_str.replace(_lazy_signal, "")
            content = content.replace(pro_str, rep_new_str)
            f_r.write(content)

    def check_lazy_completion(self, pro_name: str) -> bool:
        m_file_path: str = self.file_full_path
        if m_file_path.endswith(".h"):
            m_file_path = m_file_path.replace(".h", ".m")
        if not os.path.exists(m_file_path):
            print(f"对应的文件不存在 {m_file_path}")
            return True
        # m_file_content = ""
        with open(m_file_path, 'r') as f:
            m_file_content = f.read()
        re_imp_str = r'- {0,2}\(.+?\)%s\s*\{' % pro_name
        re_imp = re.compile(re_imp_str)
        res = re_imp.findall(m_file_content)
        return res is not None and len(res) > 0

    def add_lazy_code(self, pro_type: str, pro_name: str):
        m_file_path: str = self.file_full_path
        pro_class = pro_type.replace(" ", "")
        pro_class = pro_class.replace("*", "")
        if m_file_path.endswith(".h"):
            m_file_path = m_file_path.replace(".h", ".m")
        if not os.path.exists(m_file_path):
            print(f"对应的文件不存在 {m_file_path}")
            return True
        # m_file_content = ""
        with open(m_file_path, 'r') as f:
            m_file_content = f.read()
        re_method_imp = re.compile(r'- {0,2}\(.+?\)\w+?\s*\{[\w\W]+?\n\}')
        res = re_method_imp.findall(m_file_content, re.MULTILINE)
        code_str = _get_code_str.replace(_ret_rep, pro_type)
        code_str = code_str.replace(_ins_rep, pro_name)
        code_str = code_str.replace(_class_rep, pro_class)
        if len(res) > 0:
            last_code = res[-1]
            m_file_content = m_file_content.replace(last_code, last_code + code_str)
        else:
            re_imp = re.compile(r'@implementation {1,2}[\w\W]+?@end')
            res = re_imp.findall(m_file_content)
            if len(res) > 0:
                tmp_content = res[-1]
                target_content = tmp_content.replace(_imp_end, code_str + _imp_end)
                m_file_content = m_file_content.replace(tmp_content, target_content)
        with open(m_file_path, 'w') as f:
            f.write(m_file_content)

    @staticmethod
    def _get_pro_info(pro_str: str) -> (str, str):
        pure_pro = pro_str.replace(_lazy_signal, "")
        names = re_name_in_pro.findall(pure_pro)
        name = ""
        if len(names) > 0:
            name = names[-1]
        types = re_type_in_pro.findall(pure_pro)
        pro_type = ""
        if len(types) > 0:
            pro_type = types[-1]
        return pro_type, name

    def generate(self):
        need, pro_str = self.need_lazy()
        if need:
            pro_type, pro_value = self._get_pro_info(pro_str)
            is_impl = self.check_lazy_completion(pro_value)
            self.clean_lazy(pro_str)
            if is_impl:
                print("lazy load method has been implemented")
            else:
                self.add_lazy_code(pro_type, pro_value)
                print("")


def oc_main():
    if len(sys.argv) > 1:
        file_full_path = sys.argv[-1]
        print(file_full_path)
        if not os.path.exists(file_full_path):
            return
        oc_lazy = OCLazyGen(file_full_path)
        oc_lazy.generate()


if __name__ == '__main__':
    oc_main()
